package com.itheima.atte.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.atte.dto.AttendGroupDTO;
import com.itheima.atte.dto.AttendGroupPartDTO;
import com.itheima.atte.entity.AttendGroup;
import com.itheima.atte.entity.AttendGroupPart;
import com.itheima.atte.enums.AttendEnums;
import com.itheima.atte.mapper.AttendGroupMapper;
import com.itheima.atte.service.IAttendGroupPartService;
import com.itheima.atte.service.IAttendGroupService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.common.exception.NcException;
import com.itheima.common.exception.enums.ResponseEnum;
import com.itheima.common.threadlocal.UserHolder;
import com.itheima.common.util.BeanHelper;
import com.itheima.common.util.IpUtil;
import com.itheima.common.vo.PageResult;
import com.itheima.common.vo.Result;
import com.itheima.sys.client.SysClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 考勤组信息表 考勤-考勤组信息表 服务实现类
 * </p>
 *
 * @author itheima
 * @since 2020-12-22
 */
@Service
public class AttendGroupServiceImpl extends ServiceImpl<AttendGroupMapper, AttendGroup> implements IAttendGroupService {

    @Autowired
    private SysClient sysClient;

    @Autowired
    private IAttendGroupPartService attendGroupPartService;


    @Override
    @Transactional
    public PageResult<AttendGroupDTO> queryByPage(Integer page, Integer pageSize) {
        Long companyId = UserHolder.getCompanyId();
        //1.根据企业ID 查询考勤组数量
        QueryWrapper<AttendGroup> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(AttendGroup::getCompanyId, companyId);
        int count = this.count(queryWrapper);
        if (count == 0) {
            //1.1如果为0 需要添加默认考勤组
            AttendGroup attendGroup = this.buildDefaultAttendGroup(companyId);
            boolean b = this.save(attendGroup);
            if (!b) {
                throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
            }
            //1.2 将默认考勤组关联给部门（顶级部门）
            List<Long> departmentIds = sysClient.queryDepartmentIds().getData();
            List<AttendGroupPart> attendGroupParts = new ArrayList<>();
            for (Long departmentId : departmentIds) {
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectId(departmentId);
                attendGroupPart.setAttendType(AttendEnums.ATTEND_YES.value());
                attendGroupPart.setObjectType(AttendEnums.ATTEND_USER_TYPE_DEP.value());
                attendGroupParts.add(attendGroupPart);
            }
            boolean b1 = attendGroupPartService.saveBatch(attendGroupParts);
            if (!b1) {
                throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
            }
        }
        //2.如果有考勤组数据 执行分页查询
        IPage<AttendGroup> iPage = new Page<>(page, pageSize);
        iPage = this.page(iPage, queryWrapper);
        List<AttendGroup> attendGroups = iPage.getRecords();
        if (!CollectionUtils.isEmpty(attendGroups)) {
            List<AttendGroupDTO> attendGroupDTOS = BeanHelper.copyWithCollection(attendGroups, AttendGroupDTO.class);
            return new PageResult<>(iPage.getTotal(), iPage.getPages(), attendGroupDTOS);
        }
        return null;
    }


    /**
     * 构建默认考勤组对象
     *
     * @param companyId
     * @return
     */
    private AttendGroup buildDefaultAttendGroup(Long companyId) {
        AttendGroup attendGroup = new AttendGroup();
        attendGroup.setName("默认考勤组");
        attendGroup.setCompanyUserId(UserHolder.getCompanyUserId());
        attendGroup.setAddressRange(400);
        attendGroup.setCompanyId(UserHolder.getCompanyId());
        attendGroup.setCreateTime(new Date());
        //查询当前企业地址 根据地址调用BMapUtil工具类获取坐标信息
        attendGroup.setLat(new BigDecimal(10.000));
        attendGroup.setLng(new BigDecimal(20.000));
        attendGroup.setStartWorkTime("09:00:00");
        attendGroup.setOffWorkTime("18:00:00");
        attendGroup.setAllowLateMinutes(10);
        attendGroup.setLateMinutes(20);
        attendGroup.setWorkdays("1,1,1,1,1,0,0");
        return attendGroup;
    }


    /**
     * 保存考勤组
     *
     * @param attendGroupDTO
     */
    @Override
    @Transactional
    public void saveAttendGroup(AttendGroupDTO attendGroupDTO) {
        Long companyId = UserHolder.getCompanyId();
        //1.保存考勤组记录
        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);
        attendGroup.setCompanyId(companyId);
        attendGroup.setCompanyUserId(UserHolder.getCompanyUserId());
        attendGroup.setUpdateUserId(UserHolder.getCompanyUserId());
        boolean b = this.save(attendGroup);
        if (!b) {
            throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
        }

        //2.将考勤组 关联给用户/部门
        //2.1 处理参与考勤人员/部门
        List<AttendGroupPartDTO> joinParticipates = attendGroupDTO.getParticipates();

        List<AttendGroupPart> joinAttendGroupParts = new ArrayList<>();
        for (AttendGroupPartDTO joinParticipate : joinParticipates) {
            //先判断当前对象（部门，员工）是否已经关联到考勤组
            QueryWrapper<AttendGroupPart> attendGroupPartQueryWrapper = new QueryWrapper<>();
            attendGroupPartQueryWrapper.lambda().eq(AttendGroupPart::getObjectType, joinParticipate.getObjectType());
            attendGroupPartQueryWrapper.lambda().eq(AttendGroupPart::getObjectId, joinParticipate.getObjectId());
            attendGroupPartQueryWrapper.lambda().eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_YES.value());
            int count = attendGroupPartService.count(attendGroupPartQueryWrapper);
            if (count > 0) {
                boolean b1 = attendGroupPartService.remove(attendGroupPartQueryWrapper);
                if (!b1) {
                    throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
                }
            }
            //给对象 新关联考勤组
            AttendGroupPart attendGroupPart = new AttendGroupPart();
            attendGroupPart.setAttendGroupId(attendGroup.getId());
            attendGroupPart.setObjectType(joinParticipate.getObjectType());
            attendGroupPart.setObjectId(joinParticipate.getObjectId());
            attendGroupPart.setAttendType(AttendEnums.ATTEND_YES.value());
            joinAttendGroupParts.add(attendGroupPart);
        }
        boolean b1 = attendGroupPartService.saveBatch(joinAttendGroupParts);
        if (!b1) {
            throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
        }

        // 2.2 处理不参与考勤人员/部门
        List<AttendGroupPartDTO> notJoinParticipates = attendGroupDTO.getNotParticipates();

        List<AttendGroupPart> notJoinAttendGroupParts = new ArrayList<>();
        for (AttendGroupPartDTO joinParticipate : notJoinParticipates) {
            //先判断当前对象（部门，员工）是否已经关联到考勤组
            QueryWrapper<AttendGroupPart> attendGroupPartQueryWrapper = new QueryWrapper<>();
            attendGroupPartQueryWrapper.lambda().eq(AttendGroupPart::getObjectType, joinParticipate.getObjectType());
            attendGroupPartQueryWrapper.lambda().eq(AttendGroupPart::getObjectId, joinParticipate.getObjectId());
            attendGroupPartQueryWrapper.lambda().eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_NO.value());
            int count = attendGroupPartService.count(attendGroupPartQueryWrapper);
            if (count == 0) {
                //给对象 新关联考勤组
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectType(joinParticipate.getObjectType());
                attendGroupPart.setObjectId(joinParticipate.getObjectId());
                attendGroupPart.setAttendType(AttendEnums.ATTEND_NO.value());
                notJoinAttendGroupParts.add(attendGroupPart);

            }
        }
        boolean b2 = attendGroupPartService.saveBatch(notJoinAttendGroupParts);
        if (!b2) {
            throw new NcException(ResponseEnum.INSERT_OPERATION_FAIL);
        }
    }



    @Override
    public AttendGroupDTO queryAttendGroupByCompanyUserId(Long companyUserId) {
        //1、出现当前用户是否加入考勤组
        AttendGroupPart attendGroupPart = this.getGroupPartByType(companyUserId, AttendEnums.ATTEND_USER_TYPE_USER, AttendEnums.ATTEND_YES);
        if (attendGroupPart == null) {
            //2、如果没有用户级别，查找用户对应的部门是否有加入考勤组
            //2.1、通过远程调用系统微服务 获得当前用户的部门等级数组从低到高->优先级从高到低
            Long[] departmentIdArr = sysClient.queryDepartmentsByUserId(companyUserId).getData();
            if (departmentIdArr == null) {
                //说明该用户未加入部门 直接返回企业默认考勤组
                QueryWrapper<AttendGroup> queryWrapper = new QueryWrapper<>();
                queryWrapper.lambda().eq(AttendGroup::getName, "默认考勤组");
                queryWrapper.lambda().eq(AttendGroup::getCompanyId, UserHolder.getCompanyId());
                AttendGroup attendGroup = this.getOne(queryWrapper);
                return BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);
            }
            //2.2找用户上级部门是否加入考勤组
            for (Long departmentId : departmentIdArr) {
                attendGroupPart = this.getGroupPartByType(departmentId, AttendEnums.ATTEND_USER_TYPE_DEP, AttendEnums.ATTEND_YES);
                if (attendGroupPart != null) {
                    break;
                }
            }
        }
        if (attendGroupPart != null) {
            AttendGroup attendGroup = this.getById(attendGroupPart.getAttendGroupId());
            return BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);
        }
        //当前用户以及所属部门都未加入考勤组
        throw new RuntimeException("当前用户未加入考勤组,请管理员添加！");
    }

    /**
     * 寻找用户或者部门考勤组
     *
     * @return
     */
    private AttendGroupPart getGroupPartByType(Long objectId, AttendEnums attendPartObjType, AttendEnums joinType) {
        QueryWrapper<AttendGroupPart> wrapper = new QueryWrapper<AttendGroupPart>();
        wrapper.lambda().eq(AttendGroupPart::getObjectId, objectId);
        wrapper.lambda().eq(AttendGroupPart::getAttendType, joinType.value());
        wrapper.lambda().eq(AttendGroupPart::getObjectType, attendPartObjType.value());
        List<AttendGroupPart> attendGroupPartList = attendGroupPartService.list(wrapper);
        if (attendGroupPartList.size() > 0) {
            return attendGroupPartList.get(0);
        } else {
            return null;
        }
    }
}
